{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Project 3:  Implement SLAM \n",
    "\n",
    "---\n",
    "\n",
    "## Project Overview\n",
    "\n",
    "In this project, you'll implement SLAM for robot that moves and senses in a 2 dimensional, grid world!\n",
    "\n",
    "SLAM gives us a way to both localize a robot and build up a map of its environment as a robot moves and senses in real-time. This is an active area of research in the fields of robotics and autonomous systems. Since this localization and map-building relies on the visual sensing of landmarks, this is a computer vision problem. \n",
    "\n",
    "Using what you've learned about robot motion, representations of uncertainty in motion and sensing, and localization techniques, you will be tasked with defining a function, `slam`, which takes in six parameters as input and returns the vector `mu`. \n",
    "> `mu` contains the (x,y) coordinate locations of the robot as it moves, and the positions of landmarks that it senses in the world\n",
    "\n",
    "You can implement helper functions as you see fit, but your function must return `mu`. The vector, `mu`, should have (x, y) coordinates interlaced, for example, if there were 2 poses and 2 landmarks, `mu` will look like the following, where `P` is the robot position and `L` the landmark position:\n",
    "```\n",
    "mu =  matrix([[Px0],\n",
    "              [Py0],\n",
    "              [Px1],\n",
    "              [Py1],\n",
    "              [Lx0],\n",
    "              [Ly0],\n",
    "              [Lx1],\n",
    "              [Ly1]])\n",
    "```\n",
    "\n",
    "You can see that `mu` holds the poses first `(x0, y0), (x1, y1), ...,` then the landmark locations at the end of the matrix; we consider a `nx1` matrix to be a vector.\n",
    "\n",
    "## Generating an environment\n",
    "\n",
    "In a real SLAM problem, you may be given a map that contains information about landmark locations, and in this example, we will make our own data using the `make_data` function, which generates a world grid with landmarks in it and then generates data by placing a robot in that world and moving and sensing over some numer of time steps. The `make_data` function relies on a correct implementation of robot move/sense functions, which, at this point, should be complete and in the `robot_class.py` file. The data is collected as an instantiated robot moves and senses in a world. Your SLAM function will take in this data as input. So, let's first create this data and explore how it represents the movement and sensor measurements that our robot takes.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create the world\n",
    "\n",
    "Use the code below to generate a world of a specified size with randomly generated landmark locations. You can change these parameters and see how your implementation of SLAM responds! \n",
    "\n",
    "`data` holds the sensors measurements and motion of your robot over time. It stores the measurements as `data[i][0]` and the motion as `data[i][1]`.\n",
    "\n",
    "#### Helper functions\n",
    "\n",
    "You will be working with the `robot` class that may look familiar from the first notebook, \n",
    "\n",
    "In fact, in the `helpers.py` file, you can read the details of how data is made with the `make_data` function. It should look very similar to the robot move/sense cycle you've seen in the first notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " \n",
      "Landmarks:  [[17, 72], [26, 59], [38, 44], [30, 48], [70, 19]]\n",
      "Robot: [x=7.42799 y=42.80049]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from helpers import make_data\n",
    "\n",
    "# your implementation of slam should work with the following inputs\n",
    "# feel free to change these input values and see how it responds!\n",
    "\n",
    "# world parameters\n",
    "num_landmarks      = 5        # number of landmarks\n",
    "N                  = 20       # time steps\n",
    "world_size         = 100.0    # size of world (square)\n",
    "\n",
    "# robot parameters\n",
    "measurement_range  = 50.0     # range at which we can sense landmarks\n",
    "motion_noise       = 2.0      # noise in robot motion\n",
    "measurement_noise  = 2.0      # noise in the measurements\n",
    "distance           = 20.0     # distance by which robot (intends to) move each iteratation \n",
    "\n",
    "\n",
    "# make_data instantiates a robot, AND generates random landmarks for a given world size and number of landmarks\n",
    "data = make_data(N, num_landmarks, world_size, measurement_range, motion_noise, measurement_noise, distance)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### A note on `make_data`\n",
    "\n",
    "The function above, `make_data`, takes in so many world and robot motion/sensor parameters because it is responsible for:\n",
    "1. Instantiating a robot (using the robot class)\n",
    "2. Creating a grid world with landmarks in it\n",
    "\n",
    "**This function also prints out the true location of landmarks and the *final* robot location, which you should refer back to when you test your implementation of SLAM.**\n",
    "\n",
    "The `data` this returns is an array that holds information about **robot sensor measurements** and **robot motion** `(dx, dy)` that is collected over a number of time steps, `N`. You will have to use *only* these readings about motion and measurements to track a robot over time and find the determine the location of the landmarks using SLAM. We only print out the true landmark locations for comparison, later.\n",
    "\n",
    "\n",
    "In `data` the measurement and motion data can be accessed from the first and second index in the columns of the data array. See the following code for an example, where `i` is the time step:\n",
    "```\n",
    "measurement = data[i][0]\n",
    "motion = data[i][1]\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Example measurements: \n",
      " [[0, -32.21305083681477, 21.056246905371356], [1, -23.140212764757138, 9.218653173161774], [2, -13.879449239244904, -7.1489382742536005], [3, -19.25429573817546, -0.742694046934548], [4, 19.131159361145517, -30.7516310732602]]\n",
      "\n",
      "\n",
      "Example motion: \n",
      " [18.151533969361356, 8.397726749491241]\n"
     ]
    }
   ],
   "source": [
    "# print out some stats about the data\n",
    "time_step = 0\n",
    "\n",
    "print('Example measurements: \\n', data[time_step][0])\n",
    "print('\\n')\n",
    "print('Example motion: \\n', data[time_step][1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try changing the value of `time_step`, you should see that the list of measurements varies based on what in the world the robot sees after it moves. As you know from the first notebook, the robot can only sense so far and with a certain amount of accuracy in the measure of distance between its location and the location of landmarks. The motion of the robot always is a vector with two values: one for x and one for y displacement. This structure will be useful to keep in mind as you traverse this data in your implementation of slam."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize Constraints\n",
    "\n",
    "One of the most challenging tasks here will be to create and modify the constraint matrix and vector: omega and xi. In the second notebook, you saw an example of how omega and xi could hold all the values the define the relationships between robot poses `xi` and landmark positions `Li` in a 1D world, as seen below, where omega is the blue matrix and xi is the pink vector.\n",
    "\n",
    "<img src='images/motion_constraint.png' width=\"50%\" height=\"50%\"/>\n",
    "\n",
    "\n",
    "In *this* project, you are tasked with implementing constraints for a 2D world. We are referring to robot poses as `Px, Py` and landmark positions as `Lx, Ly`, and one way to approach this challenge is to add *both* x and y locations in the constraint matrices.\n",
    "\n",
    "<img src='images/constraints2D.png' width=\"50%\" height=\"50%\"/>\n",
    "\n",
    "You may also choose to create two of each omega and xi (one for x and one for y positions)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### TODO: Write a function that initializes omega and xi\n",
    "\n",
    "Complete the function `initialize_constraints` so that it returns `omega` and `xi` constraints for the starting position of the robot. Any values that we do not yet know should be initialized with the value `0`. You may assume that our robot starts out in exactly the middle of the world with 100% confidence (no motion or measurement noise at this point). The inputs `N` time steps, `num_landmarks`, and `world_size` should give you all the information you need to construct intial constraints of the correct size and starting values.\n",
    "\n",
    "*Depending on your approach you may choose to return one omega and one xi that hold all (x,y) positions *or* two of each (one for x values and one for y); choose whichever makes most sense to you!*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def initialize_constraints(N, num_landmarks, world_size):\n",
    "    ''' This function takes in a number of time steps N, number of landmarks, and a world_size,\n",
    "        and returns initialized constraint matrices, omega and xi.'''\n",
    "    \n",
    "    ## Recommended: Define and store the size (rows/cols) of the constraint matrix in a variable\n",
    "    \n",
    "    ## TODO: Define the constraint matrix, Omega, with two initial \"strength\" values\n",
    "    ## for the initial x, y location of our robot\n",
    "    size = N+num_landmarks\n",
    "    omega = np.zeros((size*2,size*2))\n",
    "    \n",
    "    omega[0][0] = omega[1][1] = 1\n",
    "\n",
    "    ## TODO: Define the constraint *vector*, xi\n",
    "    ## you can assume that the robot starts out in the middle of the world with 100% confidence\n",
    "    xi = np.zeros((size*2))\n",
    "\n",
    "    xi[0:2] = [world_size/2,world_size/2]\n",
    "\n",
    "    return omega, xi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Test as you go\n",
    "\n",
    "It's good practice to test out your code, as you go. Since `slam` relies on creating and updating constraint matrices, `omega` and `xi` to account for robot sensor measurements and motion, let's check that they initialize as expected for any given parameters.\n",
    "\n",
    "Below, you'll find some test code that allows you to visualize the results of your function `initialize_constraints`. We are using the [seaborn](https://seaborn.pydata.org/) library for visualization.\n",
    "\n",
    "**Please change the test values of N, landmarks, and world_size and see the results**. Be careful not to use these values as input into your final smal function.\n",
    "\n",
    "This code assumes that you have created one of each constraint: `omega` and `xi`, but you can change and add to this code, accordingly. The constraints should vary in size with the number of time steps and landmarks as these values affect the number of poses a robot will take `(Px0,Py0,...Pxn,Pyn)` and landmark locations `(Lx0,Ly0,...Lxn,Lyn)` whose relationships should be tracked in the constraint matrices. Recall that `omega` holds the weights of each variable and `xi` holds the value of the sum of these variables, as seen in Notebook 2. You'll need the `world_size` to determine the starting pose of the robot in the world and fill in the initial values for `xi`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import data viz resources\n",
    "import matplotlib.pyplot as plt\n",
    "from pandas import DataFrame\n",
    "import seaborn as sns\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# define a small N and world_size (small for ease of visualization)\n",
    "N_test = 5\n",
    "num_landmarks_test = 2\n",
    "small_world = 10\n",
    "\n",
    "# initialize the constraints\n",
    "initial_omega, initial_xi = initialize_constraints(N_test, num_landmarks_test, small_world)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fae458220f0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGfCAYAAACNytIiAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3X98nXV99/H3p6QhKAhumJNKj9UtdZO2ThSZ3m6WFruGppZ2nRvobn9R45j4Y7opXXdXKTeoc9PbTVhJW5W5qUMdWtsY9FFb21VBOsW2gNyk3DWNNCdOHP4ATEk+9x85iSFNzkmunuvX+b6ePq4HuXKdXO/rk56c8/H7va7rmLsLAAAgLbPSPgAAABA2mhEAAJAqmhEAAJAqmhEAAJAqmhEAAJAqmhEAAJAqmhEAADBtZvZxMxsws8NTbDcz+wcz6zGzg2b2wmr7pBkBAAAz8UlJbRW2XyppfnnpkPRP1XZIMwIAAKbN3fdKerjCQy6T9M8+4g5J55jZnEr7bKjlAU6BW7wCAEJjSQWdccHVNX2fffzuG9+skRGNUZ3u3jmDXZwn6di49b7y945P9QNJNCM644Krk4g5yWPf/Zgk6fEnUolXU/m3G3J+Wtnkh52fhec++WG/9uRZufGYSfMx0WSNWMWGKee/MgAAAmeZO+OiT1Jx3PpcSQ9V+oHMVQAAAHJtu6TXlq+qeYmkR9x9yikaiZERAADyzRI7PaUcZ5+RdLGkc82sT9J7Jc2WJHffLKlL0gpJPZIelfSGavukGQEAIM8SnqZx9yuqbHdJb5nJPpmmAQAAqWJkBACAPEt4miYONCMAAORZ9q6mmbH8VwAAAHIts83I5ve+Rj/Y9X4d+Nxfp3YM+/ft1ar25VrZtkzbtpzK/V/ylU0++eTzt09+OvmRmNV2SUFmm5FPffkOXfaWG1PLHxoa0g3Xb9JNm7fqtu071d21Q0d6euo+m3zyyedvn/x08iOzWbVdUlA11cx+28zeU/444I+Wv35e3Ae2/ztH9PAjj8YdM6XDhw6qWJynucWiZjc2qm1Fu/bs3lX32eSTTz5/++Snkx+yis2Imb1H0mc1cp/5b0u6q/z1Z8zsmvgPLz0DpZJa5rSMrTcXCiqVSnWfTT755PO3T346+ZHVwTRNtatprpS0wN1PjP+mmX1Y0j2SPjDZD5lZh8qf+HfzzTfX4DCT55N8po8l9I+UZjb55JPP3z756eRHFsDVNMOSnjnJ9+eUt03K3Tvd/UJ3v7Cjo2Oqh2VaodCi/uP9Y+sDpZKam5vrPpt88snnb5/8dPJDVq0ZeYekXWb2FTPrLC/dknZJenv8h5eeBQsXqbf3qPr6junE4KC6u3Zq8ZKldZ9NPvnk87dPfjr5kdX7NI27d5vZcyVdJOk8jZwv0ifpLncfivPAbnn/6/X7L5qvc885Uz3d1+m6zV265YvfijPySRoaGrR+w0Zd1bFOw8NDWr1mrVpb59d9Nvnkk8/fPvnp5EdWB9M0NvJ5NrHyMy64Ou6MST323Y9Jkh5/IpV4NZVbvZDz08omP+z8LDz3yQ/7tUcj/+c9EWf83v+q6Rv5Y/9xXeLDI9wOHgCAPMvDSbZV0IwAAJBndTBNk/8KAABArjEyAgBAntXByAjNCAAAeTYr/+eM5L+dAgAAucbICAAAecY0DQAASBWX9k7P6M3H0tKUcssVcn7ItZNPPvlhZmPmEvnnSvsugNwBNr38tO+CSH6Y+Vl47pMf9mtPopimAQAAqaqDaZr8t1MAACDXGBkBACDPmKYBAACpqoNpGpoRAADyrA5GRvJfAQAAyDVGRgAAyDOmaQAAQKqYponX/n17tap9uVa2LdO2LZ2JZm9+72v0g13v14HP/XWiuaPSrJ188slPLz/k2skPV2abkaGhId1w/SbdtHmrbtu+U91dO3Skpyex/E99+Q5d9pYbE8sbL+3aySef/HTyQ66d/FNgVtslBZltRg4fOqhicZ7mFoua3diothXt2rN7V2L5+79zRA8/8mhieeOlXTv55JOfTn7ItZN/CmxWbZcURE41szfU8kAmGiiV1DKnZWy9uVBQqVSKMzIz0q6dfPLJTyc/5NrJD9uptEDXTrXBzDrM7ICZHejsjDbn5vLJ9htpX3mTdu3kk09+Ovkh107+KaiDkZGKV9OY2cGpNkkqTPVz7t4pabQL8SifnlgotKj/eP/Y+kCppObm5pnvKIfSrp188slPJz/k2sk/BXlomKqo1gIVJL1W0isnWX4c54EtWLhIvb1H1dd3TCcGB9XdtVOLlyyNMzIz0q6dfPLJTyc/5NrJD1u1+4zskHSmu989cYOZ7YnliMoaGhq0fsNGXdWxTsPDQ1q9Zq1aW+fHGfkkt7z/9fr9F83XueecqZ7u63Td5i7d8sVvJZKddu3kk09+Ovkh107+KaiD+4yY+8lzZDUWaZqmFprKrdYZF1ydSv5j3/2YJCnt+tPMTyub/LDzs/DcJz/s1x6NnM6QiDNWd9b0jfyxL3YkPu+T/3YKAADkGreDBwAgz+pgmoZmBACAPAvgahoAAIBYMTICAECO5eLGbFXQjAAAkGP10IwwTQMAAFLFyAgAAHmW/4GRZJqRppRbntGbj6Ul7frTzA+5dvLJJz/M7KTVwzRNIv9cId8FMPT8tO+CSH6Y+Vl47pMf9msPZoZfGQAAOcbICAAASFU9NCNcTQMAAFLFyAgAADlWDyMjNCMAAORZ/nsRpmkAAEC6GBkBACDHmKYBAACpqodmJNPTNPv37dWq9uVa2bZM27Z0BpUfcu3kkx9yfsi1kx+uzDYjQ0NDuuH6Tbpp81bdtn2nurt26EhPTxD5IddOPvkh54dcO/nRmVlNlzRkthk5fOigisV5mlssanZjo9pWtGvP7l1B5IdcO/nkh5wfcu3kRxdEM2Jmv21ml5jZmRO+3xbfYUkDpZJa5rSMrTcXCiqVSnFGZiY/5NrJJz/k/JBrJz9sFZsRM3ubpC9Jequkw2Z22bjNN1T4uQ4zO2BmBzo7o825uXyy/UbaV97yQ66dfPJDzg+5dvJPgdV4SUG1q2neJOlF7v5zM3u2pM+b2bPd/aOqcMju3ilptAvxKJ+eWCi0qP94/9j6QKmk5ubmme8oojTzQ66dfPJDzg+5dvKjy0XDVEW1aZrT3P3nkuTuRyVdLOlSM/uwYu6fFixcpN7eo+rrO6YTg4Pq7tqpxUuWxhmZmfyQayef/JDzQ66d/LBVGxnpN7MXuPvdklQeIVkp6eOSFsV6YA0NWr9ho67qWKfh4SGtXrNWra3z44zMTH7ItZNPfsj5IddOfnT1MDJi7ifPkY1tNJsr6Ql3759k28vcff80MiJN09RCU7nVIj+9/LSyyQ87PwvPffLDfu1RgmdfNL/x1qnfyCMY+PgfJ97dVJymcfe+yRqR8rbpNCIAAKCOmFmbmd1vZj1mds0k259lZrvN7LtmdtDMVlTbZ2bvMwIAAKYhwatpzOw0STdKulTS+ZKuMLPzJzzsbyTd6u4XSLpc0k3VSuCzaQAAyLGEzxm5SFKPuz9Yzv6spMsk3TvuMS7paeWvz5b0ULWdMjICAADGjL9XWHnpGLf5PEnHxq33lb833vsk/amZ9Unq0si9yipiZAQAgByr9cjIhHuFnRQ32Y9MWL9C0ifd/e/N7KWSPmVmC919eKpMmhEAAHIs4WmaPknFcetzdfI0zJWS2iTJ3b9lZk2SzpU0MNVOmaYBAADTdZek+Wb2HDNr1MgJqtsnPKZX0iWSZGbPk9Qk6UeVdsrICAAAOZbo5/e4P2FmV0u6XdJpkj7u7veY2SZJB9x9u6R3SdpiZn+hkSmc13ulm5qpyk3PanXscQcAAJAxiXUIz/yzf6/p++xDm/8wWzc9AwAAiFsi0zQh35I49Py0b8lMfpj5WXjukx/2a0+S6uGzaThnBACAHKuHZoRpGgAAkCpGRgAAyLF6GBmhGQEAIM/y34vQjAAAkGf1MDLCOSMAACBVjIwAAJBjjIzEbP++vVrVvlwr25Zp25apPkCwPvNDrp188kPOD7l28qMxs5ouachsMzI0NKQbrt+kmzZv1W3bd6q7a4eO9PQEkR9y7eSTH3J+yLWTH7bMNiOHDx1UsThPc4tFzW5sVNuKdu3ZvSuI/JBrJ5/8kPNDrp386IIYGTGzi8zsxeWvzzezd5rZirgPbKBUUsuclrH15kJBpVIp7thM5IdcO/nkh5wfcu3knwKr8ZKCis2Imb1X0j9I+icze7+kj0k6U9I1Zrahws91mNkBMzvQ2Rltzs0n+bDfRD8mOcX8kGsnn/yQ80OunfywVbua5o8kvUDS6ZL6Jc1195+a2Yck3Snp+sl+yN07JY12IR7lA4sKhRb1H+8fWx8oldTc3DzzHUWUZn7ItZNPfsj5IddOfnT10DBVm6Z5wt2H3P1RSUfc/aeS5O6PSRqO88AWLFyk3t6j6us7phODg+ru2qnFS5bGGZmZ/JBrJ5/8kPNDrp386OrhnJFqIyODZvaUcjPyotFvmtnZirkZaWho0PoNG3VVxzoNDw9p9Zq1am2dH2dkZvJDrp188kPOD7l28sNm7ifPkY1tNDvd3X85yffPlTTH3Q9NIyPSNE0tNJVbLfLTy08rm/yw87Pw3Cc/7NceJXgqaOtffmXqN/IIev7u0sSHRyqOjEzWiJS//1+S/iuWIwIAANMWwjkjAAAAseKzaQAAyLE6GBihGQEAIM+YpgEAADhFjIwAAJBjdTAwQjMCAECezZqV/26EaRoAAJCqREZGmlIefyE/zGzyySc/3Py0a08S0zQAACBV9XA1TSLNSMi3JA49P+1bMpMfZn4Wnvvkh/3ag5nhVwYAQI7VwcAIzQgAAHlWD9M0XE0DAABSxcgIAAA5Vg8jIzQjAADkWB30IkzTAACAdDEyAgBAjjFNAwAAUlUHvUi2p2n279urVe3LtbJtmbZt6QwqP+TaySc/5PyQayc/XJltRoaGhnTD9Zt00+atum37TnV37dCRnp4g8kOunXzyQ84PuXbyozOzmi5pmHEzYmb/HMeBTHT40EEVi/M0t1jU7MZGta1o157du5KITj0/5NrJJz/k/JBrJz86s9ouaajYjJjZ9gnLlyX94eh6nAc2UCqpZU7L2HpzoaBSqRRnZGbyQ66dfPJDzg+5dvLDVu0E1rmS7pW0VZJLMkkXSvr7Sj9kZh2SOiTp5ptv1mvf2DHjA3P5ZPud8X6iSjM/5NrJJz/k/JBrJz+6PBxjNdWakQslvV3SBkl/5e53m9lj7v6NSj/k7p2SRs/88SifnlgotKj/eP/Y+kCppObm5pnvKKI080OunXzyQ84PuXbyo6uDXqTyNI27D7v7RyS9QdIGM/uYEroceMHCRertPaq+vmM6MTio7q6dWrxkaRLRqeeHXDv55IecH3Lt5IdtWo2Fu/dJepWZtUv6abyHNKKhoUHrN2zUVR3rNDw8pNVr1qq1dX4S0annh1w7+eSHnB9y7eRHVw/TNOZ+8hxZjUWapqmFpnKrRX56+Wllkx92fhae++SH/dqjkXMsE/GSD3yjpm/kd1yzOPHuJrP3GQEAAGHgdvAAAORYPUzT0IwAAJBjddCLME0DAADSxcgIAAA5xjQNAABIVR30IkzTAACAdCUyMtKU8vgL+WFmk08++eHmp117kpimAQAAqaIZmaaQ7wIYen7ad0EkP8z8LDz3yQ/7tQczw68MAIAcq4OBEZoRAADyrB6mabiaBgAApIqREQAAcqwOBkZoRgAAyLN6mKahGQEAIMfqoBfhnBEAAJAuRkYAAMixWXUwNJLpkZH9+/ZqVftyrWxbpm1bOoPKD7l28skPOT/k2smPxqy2Sxoy24wMDQ3phus36abNW3Xb9p3q7tqhIz09QeSHXDv55IecH3Lt5IdtRs2Imf2emb3TzP4grgMadfjQQRWL8zS3WNTsxka1rWjXnt274o7NRH7ItZNPfsj5IddOfnRmVtMlDRWbETP79riv3yTpY5LOkvReM7smzgMbKJXUMqdlbL25UFCpVIozMjP5IddOPvkh54dcO/nRzbLaLtWYWZuZ3W9mPVP1Amb2x2Z2r5ndY2afrlpDle2zx33dIWmZu18r6Q8kvabCgXaY2QEzO9DZGW3OzeWT7TfSvvKWH3Lt5JMfcn7ItZOfD2Z2mqQbJV0q6XxJV5jZ+RMeM1/Sekkvc/cFkt5Rbb/VrqaZZWZP10jTYu7+I0ly91+Y2ZSfiejunZJGuxCP8umJhUKL+o/3j60PlEpqbm6e+Y4iSjM/5NrJJz/k/JBrJz+6hBumiyT1uPuD5ezPSrpM0r3jHvMmSTe6+08kyd0Hqu202sjI2ZL+U9IBSb9mZi3l8DMlxVr9goWL1Nt7VH19x3RicFDdXTu1eMnSOCMzkx9y7eSTH3J+yLWTH12tr6YZP7tRXjrGxZ0n6di49b7y98Z7rqTnmtl+M7vDzNqq1VBxZMTdnz3FpmFJa6rt/FQ0NDRo/YaNuqpjnYaHh7R6zVq1ts6PMzIz+SHXTj75IeeHXDv52TFhdmOiyQYiJs5vNUiaL+liSXMl7TOzhe7+31NlmvvJc2Q1Fmmaphaayq0W+enlp5VNftj5WXjukx/2a49inj0Yb+XNd9X0jXzHm1885bGb2Uslvc/dl5fX10uSu79/3GM2S7rD3T9ZXt8l6Rp3v2uq/Wb2PiMAAKC6hK+muUvSfDN7jpk1Srpc0vYJj/mipCWSZGbnamTa5sGKNUQpHAAAhMfdn5B0taTbJd0n6VZ3v8fMNpnZqvLDbpf0YzO7V9JuSX/l7j+utF8+mwYAgBxL+vJjd++S1DXhexvHfe2S3llepoVmBACAHKuHW6EwTQMAAFLFyAgAADk2qw6GRmhGAADIsTroRZimAQAA6UpkZKQp5fEX8sPMJp988sPNT7v2JNXDh/kl8s8V8l0AQ89P+y6I5IeZn4XnPvlhv/YkqQ56EaZpAABAugIayAIAoP5wNQ0AAEhV/lsRpmkAAEDKGBkBACDHuJoGAACkalb+exGmaQAAQLoYGQEAIMfqYZom0yMj+/ft1ar25VrZtkzbtnQGlR9y7eSTH3J+yLWTH41ZbZc0ZLYZGRoa0g3Xb9JNm7fqtu071d21Q0d6eoLID7l28skPOT/k2skPW8VmxMx+18yeVv76DDO71sy+bGYfNLOz4zyww4cOqlicp7nFomY3NqptRbv27N4VZ2Rm8kOunXzyQ84PuXbyozOzmi5pqDYy8nFJj5a//qiksyV9sPy9T8R4XBooldQyp2VsvblQUKlUijMyM/kh104++SHnh1w7+dHNstouqdRQbbu7j37c0IXu/g53/w93v1bSb0z1Q2bWYWYHzOxAZ2e0OTeXT7bfSPvKW37ItZNPfsj5IddOftiqXU1z2Mze4O6fkPQ9M7vQ3Q+Y2XMlnZjqh9y9U9JoF+JRPj2xUGhR//H+sfWBUknNzc0z31FEaeaHXDv55IecH3Lt5EdXDw1TtZGRdZIWm9kRSedL+paZPShpS3lbbBYsXKTe3qPq6zumE4OD6u7aqcVLlsYZmZn8kGsnn/yQ80OunfzorMZLGiqOjLj7I5Jeb2ZnaWRapkFSn7vHPonW0NCg9Rs26qqOdRoeHtLqNWvV2jo/7thM5IdcO/nkh5wfcu3kh83cT54jq7FI0zS10FRutchPLz+tbPLDzs/Cc5/8sF97lOAgw7p/O1zTN/Ktf7Iw8QES7sAKAECO1cEpI9m96RkAAAgDIyMAAORYPVxNQzMCAECO1UEvwjQNAABIFyMjAADk2Kw6GBqhGQEAIMfqoBdhmgYAAKQrkZGRppTHX8gPM5t88skPNz/t2pPE1TTTFPJdAEPPT/suiOSHmZ+F5z75Yb/2JKkepjjqoQYAAJBjAQ1kAQBQf5imAQAAqZqV/16EZgQAgDyrh2aEc0YAAECqGBkBACDHOGcEAACkimkaAACAU5TpZmT/vr1a1b5cK9uWaduWzqDyQ66dfPJDzg+5dvKjMavtkobMNiNDQ0O64fpNumnzVt22fae6u3boSE9PEPkh104++SHnh1w7+dHNMqvpkkoNlTaa2dvMrJjUwYx3+NBBFYvzNLdY1OzGRrWtaNee3buCyA+5dvLJDzk/5NrJD1u1kZHrJN1pZvvM7M/N7BlJHJQkDZRKapnTMrbeXCioVColFZ9qfsi1k09+yPkh105+dLNqvKShWu6DkuZqpCl5kaR7zazbzF5nZmdN9UNm1mFmB8zsQGdntDk3l0+230j7ylt+yLWTT37I+SHXTn509XDOSLVLe93dhyV9VdJXzWy2pEslXSHp7yRNOlLi7p2SRrsQj/LpiYVCi/qP94+tD5RKam5unvmOIkozP+TaySc/5PyQayc/bNVGRp7UI7n7CXff7u5XSHpWfIclLVi4SL29R9XXd0wnBgfV3bVTi5csjTMyM/kh104++SHnh1w7+dHVwwms1UZG/mSqDe7+WI2P5UkaGhq0fsNGXdWxTsPDQ1q9Zq1aW+fHGZmZ/JBrJ5/8kPNDrp386HIwk1SVuZ88R1ZjkaZpaqGp3GqRn15+Wtnkh52fhec++WG/9mjCzEKcNt7+QE3fyDctn594e8Pt4AEAyLF6uB08zQgAADmW1nketZTZO7ACAIAwMDICAECO1cHACM0IAAB5Vg/njDBNAwAAUsXICAAAOWbJXUUcG5oRAAByrB6maRJpRppSbnnIDzObfPLJDzc/7doxM4n8c4V8F8DQ89O+CyL5YeZn4blPftivPUliZAQAAKTK6uDaXq6mAQAAqWJkBACAHGOaBgAApKoOZmmYpgEAAOliZAQAgByrh0/tpRkBACDH6uGcEaZpAADAtJlZm5ndb2Y9ZnZNhcf9kZm5mV1YbZ+Zbkb279urVe3LtbJtmbZt6QwqP+TaySc/5PyQayc/GrPaLpWz7DRJN0q6VNL5kq4ws/MnedxZkt4m6c7p1JDZZmRoaEg3XL9JN23eqtu271R31w4d6ekJIj/k2sknP+T8kGsnP7pZspouVVwkqcfdH3T3QUmflXTZJI+7TtLfSnp8ejVUYGaNZvZaM3tFef3VZvYxM3uLmc2eTkBUhw8dVLE4T3OLRc1ubFTbinbt2b0rzsjM5IdcO/nkh5wfcu3kZ4eZdZjZgXFLx7jN50k6Nm69r/y98T9/gaSiu++Ybma1kZFPSGqX9HYz+5SkV2lkyOXFkrZONySKgVJJLXNaxtabCwWVSqU4IzOTH3Lt5JMfcn7ItZMfXa2nady9090vHLeMn6+abOjEf3UsNkvSRyS9ayY1VLuaZpG7P9/MGiT9UNIz3X3IzP5F0vem+qFyF9UhSTfffLNe+8aOqR46Jf9VbeP3O+P9RJVmfsi1k09+yPkh105+dAlfTdMnqThufa6kh8atnyVpoaQ95d9di6TtZrbK3Q9MtdNqzcgsM2uU9FRJT5F0tqSHJZ0uacppmnIXNdpJeZRPTywUWtR/vH9sfaBUUnNz88x3FFGa+SHXTj75IeeHXDv5uXGXpPlm9hyNDFJcLunVoxvd/RFJ546um9keSX9ZqRGRqk/TbJP0fUl3S9og6XNmtqV8MJ+deQ3Tt2DhIvX2HlVf3zGdGBxUd9dOLV6yNM7IzOSHXDv55IecH3Lt5Ec3y6ymSyXu/oSkqyXdLuk+Sbe6+z1mtsnMVkWtoeLIiLt/xMz+rfz1Q2b2z5JeIWmLu387aui0DqyhQes3bNRVHes0PDyk1WvWqrV1fpyRmckPuXbyyQ85P+TayY8u6Zkkd++S1DXhexuneOzF09mnuZ88R1ZjkaZpaqGp3GqRn15+Wtnkh52fhec++WG/9mjyEz1jseXOH9T0jfxNvzsv8RNluB08AAA5xmfTAACAVNVBL5LdO7ACAIAwMDICAECO1cOoAs0IAAA5locbs1VTDw0VAADIMUZGAADIsfyPi9CMAACQa1zaO01NKbc85IeZTT755Iebn3btmBn+uQAAyLH8j4sk1IyEfEvi0PPTviUz+WHmZ+G5T37Yrz1JqoNZGq6mAQAA6WKaBgCAHKuH+4zQjAAAkGP1MMVBMwIAQI7Vw8hIPTRUAAAgxxgZAQAgx/I/LkIzAgBArjFNE7P9+/ZqVftyrWxbpm1bOoPKD7l28skPOT/k2skPV2abkaGhId1w/SbdtHmrbtu+U91dO3SkpyeI/JBrJ5/8kPNDrp386GbVeElDZpuRw4cOqlicp7nFomY3NqptRbv27N4VRH7ItZNPfsj5IddOfnRmVtMlDVWbETP7TTP7SzP7qJn9vZn9mZmdHfeBDZRKapnTMrbeXCioVCrFHZuJ/JBrJ5/8kPNDrp38sFVsRszsbZI2S2qS9GJJZ0gqSvqWmV1c4ec6zOyAmR3o7Iw25+byyfYbaV95yw+5dvLJDzk/5NrJj85qvKSh2tU0b5L0AncfMrMPS+py94vN7GZJX5J0wWQ/5O6dkka7EI/ygUWFQov6j/ePrQ+USmpubp75jiJKMz/k2sknP+T8kGsnP7oc9EtVTeeckdGG5XRJZ0mSu/dKmh3XQUnSgoWL1Nt7VH19x3RicFDdXTu1eMnSOCMzkx9y7eSTH3J+yLWTH7ZqIyNbJd1lZndIermkD0qSmT1D0sOxHlhDg9Zv2KirOtZpeHhIq9esVWvr/DgjM5Mfcu3kkx9yfsi1kx/drDq47Zm5nzxH9qQHmC2Q9DxJh939+xEyIk3T1EJTudUiP738tLLJDzs/C8998sN+7VGCp1/sOFyq/EY+QysXFhLvbqregdXd75F0TwLHAgAAAsTt4AEAyDGrg2kamhEAAHIslKtpAAAAYsPICAAAOVYPV9PQjAAAkGNM0wAAAJwiRkYAAMixehgZSaQZaUq55SE/zGzyySc/3Py0a09SPVzayzQNAABIVSK9Y8i3JA49P+1bMpMfZn4Wnvvkh/3ak6RZ+R8Y4ZwRAADyjGkaAACAU8TICAAAOcbVNAAAIFVM0wAAAJwiRkYAAMgxrqYBAACpYpoGAADgFGW6Gdm/b69WtS/XyrZl2ralM6j8kGsnn/yQ80OunfxozGq7pCGzzcjQ0JBuuH6Tbtq8Vbdt36nurh060tOXCgg4AAASuUlEQVQTRH7ItZNPfsj5IddOfnRW4yUNmW1GDh86qGJxnuYWi5rd2Ki2Fe3as3tXEPkh104++SHnh1w7+WHLbDMyUCqpZU7L2HpzoaBSqRREfsi1k09+yPkh105+dLPMarqkUkOljWZ2tpl9wMy+b2Y/Li/3lb93ToWf6zCzA2Z2oLMz2pybyyfbb6R95S0/5NrJJz/k/JBrJz+6epimqXZp762Svi7pYnfvlyQza5H0Okmfk7Rssh9y905Jo12IR/n0xEKhRf3H+8fWB0olNTc3z3xHEaWZH3Lt5JMfcn7ItZMftmrTNM929w+ONiKS5O797v5BSc+K88AWLFyk3t6j6us7phODg+ru2qnFS5bGGZmZ/JBrJ5/8kPNDrp38U1AHQyPVRkZ+YGbvlnSLu5ckycwKkl4v6VisB9bQoPUbNuqqjnUaHh7S6jVr1do6P87IzOSHXDv55IecH3Lt5EdXDzc9M/eT58jGNpo9XdI1ki6TNDpWVZK0XdIH3P0n08iINE1TC03lVov89PLTyiY/7PwsPPfJD/u1RwmOMdx55JGp38gj+N3fPDvx7qbiyEi52XhPeXkSM3uDpE/EdFwAAGAacnCObVWncmnvtTU7CgAAEEkdnDJSeWTEzA5OtUlSofaHAwAAQlPtBNaCpOWSJp4bYpK+GcsRAQCA6auDaZpqzcgOSWe6+90TN5jZnliOCAAATFs9XE1T7QTWKytse3XtDwcAAISm2sgIAADIsHq4moZmBACAHKuDXiSZZqQp5ZaH/DCzySef/HDz064dM5PIP1fIdwEMPT/tuyCSH2Z+Fp775If92pOoOhgaoXcEACDH6uFqmlO5AysAAAiMmbWZ2f1m1mNm10yy/Z1mdq+ZHTSzXWY2r9o+aUYAAMgxs9oulbPsNEk3SrpU0vmSrjCz8yc87LuSLnT350v6vKS/rVYDzQgAADmW8GfTXCSpx90fdPdBSZ+VdNn4B7j7bnd/tLx6h6S51XZKMwIAQJ7VuBsxsw4zOzBu6RiXdp6kY+PW+8rfm8qVkr5SrQROYAUAAGPcvVNS5xSbJxs88UkfaPanki6UtLhaJs0IAAA5lvDVNH2SiuPW50p6aOKDzOwVkjZIWuzuv6y2U5oRAAByLOHbwd8lab6ZPUfSDyVdLulJn1VnZhdIullSm7sPTGenmT5nZP++vVrVvlwr25Zp25apRozqMz/k2sknP+T8kGsnP/vc/QlJV0u6XdJ9km5193vMbJOZrSo/7EOSzpT0OTO728y2T2fHcS/+2ImZLz9//Alfeskl/sCDvf7TX/zSV658pR++74EZ7WNU3vJrkZ2V/LR+9+SHnc/fPvlp/duPqz+J91e5uw4d+5nXckny2EeXzI6MHD50UMXiPM0tFjW7sVFtK9q1Z/euIPJDrp188kPOD7l28k9Bwtf2xiGzzchAqaSWOS1j682FgkqlUhD5IddOPvkh54dcO/lhi6UZGX+NcmdntDk3n+RKIUvwLJ0080OunXzyQ84PuXbyo7Ma/y8Nka+mMbOvuPulk23zJ1+j7FE+PbFQaFH/8f6x9YFSSc3NzRGONJo080OunXzyQ84PuXbyo8tBv1RVxZERM3vhFMuLJL0gzgNbsHCRenuPqq/vmE4MDqq7a6cWL1kaZ2Rm8kOunXzyQ84PuXbyw1ZtZOQuSd/Q5Ke0nFP7w/mVhoYGrd+wUVd1rNPw8JBWr1mr1tb5cUZmJj/k2sknP+T8kGsnP7o6GBiRuU96F9eRjWaHJa1x9wcm2XbM3YuT/NhEkaZpaqGp3GqRn15+Wtnkh52fhec++WG/9ijBHuG+47+Y+o08gufNeWri/U21E1jfV+Exb63toQAAgBBVnKZx989X2Pz0Gh8LAACYobSugKmlU7m099qaHQUAAIjErLZLGiqOjJjZwak2SSrU/nAAAEBoql1NU5C0XNJPJnzfJH0zliMCAADTlv9JmurNyA5JZ7r73RM3mNmeWI4IAABMXx10I9VOYL2ywrZX1/5wAABAaCLfDh4AAKSvHq6mqXjTsxqJPQAAgIxJrEPoGXispu+zrc1nJN7dJDIyEvJdAEPPT/suiOSHmZ+F5z75Yb/2YGb4lQEAkGP5n6ShGQEAIN/qoBs5lTuwAgAAnDJGRgAAyLF6uJqGZgQAgBxL6/NkaolpGgAAkCpGRgAAyLE6GBihGQEAINfqoBvJ9DTN/n17tap9uVa2LdO2LZ1B5YdcO/nkh5wfcu3kB8zd4178sRMzX37++BO+9JJL/IEHe/2nv/ilr1z5Sj983wMz2seovOXXIjsr+Wn97skPO5+/ffLT+rcfV38S769ydx39r8e9lkuSxz66ZHZk5PChgyoW52lusajZjY1qW9GuPbt3BZEfcu3kkx9yfsi1kx+dWW2XNGS2GRkoldQyp2VsvblQUKlUCiI/5NrJJz/k/JBrJz9ssTQjZtZhZgfM7EBnZ7Q5N5/kw34twZYtzfyQayef/JDzQ66d/OisxksaKl5NY2ZPk7Re0lxJX3H3T4/bdpO7//lkP+funZJGuxCP8umJhUKL+o/3j60PlEpqbm6e+Y4iSjM/5NrJJz/k/JBrJz+6HPRLVVUbGfmERhqlL0i63My+YGanl7e9JM4DW7BwkXp7j6qv75hODA6qu2unFi9ZGmdkZvJDrp188kPOD7l28sNW7T4jv+nua8tff9HMNkj6upmtivm41NDQoPUbNuqqjnUaHh7S6jVr1do6P+7YTOSHXDv55IecH3Lt5J+K/A+NmPvJc2RjG83uk7TA3YfHfe91kt4t6Ux3nzeNjEjTNLXQVG61yE8vP61s8sPOz8Jzn/ywX3uUYIfww/8enPqNPILzzmlMvLupNk3zZUlPGqNy91skvUvSYFwHBQAAwlFxmsbd3z3F97vN7IZ4DgkAAExX/idpTu3S3mtrdhQAACCSerjpWbVLew9OtUlSofaHAwAAQlPtapqCpOWSfjLh+ybpm7EcEQAAmDarg4maas3IDo1cNXP3xA1mtieWIwIAANOX/16k6gmsV1bY9uraHw4AAAhNtZERAACQYXUwMFL5pmc1EnsAAAAZk1iPMPCzEzV9n20+a3bi/U0iIyMh3wUw9Py074JIfpj5WXjukx/2aw9mhl8ZAAA5FsLVNAAAIMvy34uc0h1YAQAAThkjIwAA5FgdDIzQjAAAkGdpfZ5MLdGMAACQY/VwAivnjAAAgFQxMgIAQI7VwzRNpkdG9u/bq1Xty7WybZm2bekMKj/k2sknP+T8kGsnP2DuHvfij52Y+fLzx5/wpZdc4g882Os//cUvfeXKV/rh+x6Y0T5G5S2/FtlZyU/rd09+2Pn87ZOf1r/9uPqTeH+Vu+vhXzzhtVySPPbRJbMjI4cPHVSxOE9zi0XNbmxU24p27dm9K4j8kGsnn/yQ80OunfzozGq7pCGzzchAqaSWOS1j682FgkqlUhD5IddOPvkh54dcO/nRWY3/l4ZYmhEz6zCzA2Z2oLMz2pybT/Jhv5Zgy5Zmfsi1k09+yPkh105+2CpeTWNmLZLeK2lY0kZJb5W0VtJ9kt7u7scn+zl375Q02oV4lE9PLBRa1H+8f2x9oFRSc3PzzHcUUZr5IddOPvkh54dcO/nR1UO/VG1k5JOS7pV0TNJuSY9Jape0T9LmOA9swcJF6u09qr6+YzoxOKjurp1avGRpnJGZyQ+5dvLJDzk/5NrJj85qvKSh2n1GCu7+j5JkZn/u7h8sf/8fzezKWA+soUHrN2zUVR3rNDw8pNVr1qq1dX6ckZnJD7l28skPOT/k2skPm7mfPEc2ttHse+7+O+Wv/7e7/824bYfcfdE0MiJN09RCU7nVIj+9/LSyyQ87PwvPffLDfu1RgoMMP/vl8NRv5BGcdfqsxAdIqo2MfMnMznT3n09oRFol3R/voQEAgGrq4bNpKjYj7r5xiu/3mNnOeA4JAACE5FQu7b22ZkcBAAAiqYebnlW7tPfgVJskFWp/OAAAYCbyP0kzjatpJC2X9JMJ3zdJ34zliAAAQFCqNSM7JJ3p7ndP3GBme2I5IgAAMH11MDRS8ZwRd7/S3f9jim2vjueQAADAdCX92TRm1mZm95tZj5ldM8n2083s38rb7zSzZ1fbZ2Y/KA8AAGSLmZ0m6UZJl0o6X9IVZnb+hIddKekn7t4q6SOSPqgqKt70rEZiDwAAIGMSmzx5/Inavs82NUx97Gb2Uknvc/fl5fX1kuTu7x/3mNvLj/mWmTVI6pf0DK/QcCQxMnJKt8k3szef6j7IJz+P+SHXTj75dZCfmKYGWS0XM+swswPjlo5xcedp5PPqRvWVv6fJHuPuT0h6RNKvV6ohD9M0HdUfQj75dZkfcu3kkx96fmrcvdPdLxy3dI7bPFmjNXHEYzqPeZI8NCMAACAb+iQVx63PlfTQVI8pT9OcLenhSjulGQEAANN1l6T5ZvYcM2uUdLmk7RMes13S68pf/5Gkr1c6X0Sqfp+RLOis/hDyya/L/JBrJ5/80PMzyd2fMLOrJd0u6TRJH3f3e8xsk6QD7r5d0jZJnzKzHo2MiFxebb9JXE0DAAAwJaZpAABAqmhGAABAqjLdjFS75WzM2R83swEzO5xkbjm7aGa7zew+M7vHzN6ecH6TmX3bzL5Xzr82yfxxx3GamX3XzHakkH3UzA6Z2d1mdiCF/HPM7PNm9v3y8+ClCWb/Vrnu0eWnZvaOpPLLx/AX5efeYTP7jJk1JZz/9nL2PUnUPtnrjZn9mpl9zcweKP/36Qnnv6pc/7CZXRhXdoX8D5Wf/wfN7DYzOyfB7OvKuXeb2VfN7JlxZONXMtuMTPOWs3H6pKS2BPPGe0LSu9z9eZJeIuktCdf+S0lL3f13JL1AUpuZvSTB/FFvl3RfCrmjlrj7C9w91hfiKXxUUre7/7ak31GCvwd3v79c9wskvUjSo5JuSyrfzM6T9DZJF7r7Qo2cJFf1BLga5i+U9CZJF2nkd7/SzObHHPtJnfx6c42kXe4+X9Ku8nqS+Ycl/aGkvTHmVsr/mqSF7v58Sf9X0voEsz/k7s8v/w3skLQxpmyUZbYZ0cgLQY+7P+jug5I+K+mypMLdfa+qXBcdY/Zxd/9O+eufaeSNaOId7uLMd3f/eXl1dnlJ9ExnM5srqV3S1iRzs8DMnibp5Ro5I13uPuju/53S4Vwi6Yi7/yDh3AZJZ5TvUfAUnXwfgzg9T9Id7v5o+e6R35C0Js7AKV5vLpN0S/nrWyStTjLf3e9z9/vjypxG/lfLv39JukMj97NIKvun41afKj7WJHZZbkamc8vZumdmz5Z0gaQ7E849zczuljQg6Wvunmi+pP8j6d2ShhPOHeWSvmpm/znhVshJ+A1JP5L0ifI01VYze2rCxzDqckmfSTLQ3X8o6e8k9Uo6LukRd/9qgodwWNLLzezXzewpklboyTd5SkrB3Y9LI/8HRVJzCseQFW+U9JUkA83sejM7Juk1YmQkdlluRmZ8O9l6Y2ZnSvqCpHdM6NRj5+5D5SHKuZIuKg9dJ8LMVkoacPf/TCpzEi9z9xdqZJrwLWb28gSzGyS9UNI/ufsFkn6heIfoJ1W+odEqSZ9LOPfpGhkVeI6kZ0p6qpn9aVL57n6fRj5l9GuSuiV9TyNTp0iBmW3QyO//X5PMdfcN7l4s516dZHaIstyMTOeWs3XLzGZrpBH5V3f/97SOozw9sEfJnj/zMkmrzOyoRqbnlprZvySYL3d/qPzfAY2cL3FRgvF9kvrGjUZ9XiPNSdIulfQddy8lnPsKSf/P3X/k7ick/buk/5HkAbj7Nnd/obu/XCND+A8kmV9WMrM5klT+70AKx5AqM3udpJWSXlPtDp4x+rSktSllByPLzch0bjlbl8zMNHK+wH3u/uEU8p8xeua6mZ2hkTeH7yeV7+7r3X2uuz9bI//uX3f3xP6fsZk91czOGv1a0h9oZOg+Ee7eL+mYmf1W+VuXSLo3qfxxrlDCUzRlvZJeYmZPKf8tXKKET2Q2s+byf5+lkZM40/g9jL+l9uskfSmFY0iNmbVJeo+kVe7+aMLZ409YXqUEX/9CldnbwU91y9mk8s3sM5IulnSumfVJeq+7b0so/mWS/qekQ+XzNiTpr929K6H8OZJuKV/RNEvSre6e+OW1KSpIum3kfVANkj7t7t0JH8NbJf1ruRF/UNIbkgwvnyuxTNKbk8yVJHe/08w+L+k7Ghme/66SvzX3F8zs1yWdkPQWd/9JnGGTvd5I+oCkW83sSo00aK9KOP9hSf8o6RmSdprZ3e6+PMH89ZJOl/S18t/iHe7+Zwllryj/n4FhST+QVPNcPBm3gwcAAKnK8jQNAAAIAM0IAABIFc0IAABIFc0IAABIFc0IAABIFc0IAABIFc0IAABI1f8H9EEFQpn7PJEAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fae47876ac8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# define figure size\n",
    "plt.rcParams[\"figure.figsize\"] = (10,7)\n",
    "\n",
    "# display omega\n",
    "sns.heatmap(DataFrame(initial_omega), cmap='Blues', annot=True, linewidths=.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x7fae454ecba8>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fae45772fd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# define  figure size\n",
    "plt.rcParams[\"figure.figsize\"] = (1,7)\n",
    "\n",
    "# display xi\n",
    "sns.heatmap(DataFrame(initial_xi), cmap='Oranges', annot=True, linewidths=.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## SLAM inputs \n",
    "\n",
    "In addition to `data`, your slam function will also take in:\n",
    "* N -   The number of time steps that a robot will be moving and sensing\n",
    "* num_landmarks - The number of landmarks in the world\n",
    "* world_size - The size (w/h) of your world\n",
    "* motion_noise - The noise associated with motion; the update confidence for motion should be `1.0/motion_noise`\n",
    "* measurement_noise - The noise associated with measurement/sensing; the update weight for measurement should be `1.0/measurement_noise`\n",
    "\n",
    "#### A note on noise\n",
    "\n",
    "Recall that `omega` holds the relative \"strengths\" or weights for each position variable, and you can update these weights by accessing the correct index in omega `omega[row][col]` and *adding/subtracting* `1.0/noise` where `noise` is measurement or motion noise. `Xi` holds actual position values, and so to update `xi` you'll do a similar addition process only using the actual value of a motion or measurement. So for a vector index `xi[row][0]` you will end up adding/subtracting one measurement or motion divided by their respective `noise`.\n",
    "\n",
    "### TODO: Implement Graph SLAM\n",
    "\n",
    "Follow the TODO's below to help you complete this slam implementation (these TODO's are in the recommended order), then test out your implementation! \n",
    "\n",
    "#### Updating with motion and measurements\n",
    "\n",
    "With a 2D omega and xi structure as shown above (in earlier cells), you'll have to be mindful about how you update the values in these constraint matrices to account for motion and measurement constraints in the x and y directions. Recall that the solution to these matrices (which holds all values for robot poses `P` and landmark locations `L`) is the vector, `mu`, which can be computed at the end of the construction of omega and xi as the inverse of omega times xi: $\\mu = \\Omega^{-1}\\xi$\n",
    "\n",
    "**You may also choose to return the values of `omega` and `xi` if you want to visualize their final state!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "## TODO: Complete the code to implement SLAM\n",
    "\n",
    "## slam takes in 6 arguments and returns mu, \n",
    "## mu is the entire path traversed by a robot (all x,y poses) *and* all landmarks locations\n",
    "def slam(data, N, num_landmarks, world_size, motion_noise, measurement_noise):\n",
    "    \n",
    "    Wms = 1.0/measurement_noise\n",
    "    Wmo = 1.0/motion_noise\n",
    "    \n",
    "    ## TODO: Use your initilization to create constraint matrices, omega and xi\n",
    "    omega, xi = initialize_constraints(N, num_landmarks, world_size)\n",
    "    \n",
    "    ## TODO: Iterate through each time step in the data\n",
    "    ## get all the motion and measurement data as you iterate\n",
    "    for ts, sample in enumerate(data):\n",
    "        measurements, motion = sample\n",
    "        pose_i = 2*ts\n",
    "    \n",
    "    ## TODO: update the constraint matrix/vector to account for all *measurements*\n",
    "    ## this should be a series of additions that take into account the measurement noise\n",
    "        for m in measurements:\n",
    "            lm_j, lm_x, lm_y = m[0], m[1], m[2]\n",
    "            lm_j = 2*(N + lm_j)\n",
    "            omega[pose_i]  [pose_i]     +=  Wms   # pose_i.x <-> pose_i.x\n",
    "            omega[pose_i+1][pose_i+1]   +=  Wms   # pose_i.y <-> pose_i.y\n",
    "            omega[pose_i]  [lm_j]       += -Wms   # pose_i.x <-> lm_j.x\n",
    "            omega[pose_i+1][lm_j + 1]   += -Wms   # pose_i.y <-> lm_j.y\n",
    "            omega[lm_j]    [pose_i]     += -Wms   # lm_j.x <-> pose_i.x\n",
    "            omega[lm_j + 1][pose_i+1]   += -Wms   # lm_j.y <-> pose_i.y\n",
    "            omega[lm_j]    [lm_j]       +=  Wms   # lm_j.x <-> lm_j.x\n",
    "            omega[lm_j + 1][lm_j + 1]   +=  Wms   # lm_j.y <-> lm_j.y\n",
    "            \n",
    "            xi[pose_i]   += -lm_x*Wms\n",
    "            xi[pose_i+1] += -lm_y*Wms\n",
    "            xi[lm_j]     +=  lm_x*Wms\n",
    "            xi[lm_j+1]   +=  lm_y*Wms\n",
    "        \n",
    "    ## TODO: update the constraint matrix/vector to account for all *motion* and motion noise\n",
    "        omega[pose_i]  [pose_i]     +=  Wmo   # pose_i.x <-> pose_i.x\n",
    "        omega[pose_i+1][pose_i+1]   +=  Wmo   # pose_i.y <-> pose_i.y\n",
    "        omega[pose_i]  [pose_i+2]   += -Wmo   # pose_i.x <-> pose_i+1.x\n",
    "        omega[pose_i+1][pose_i+3]   += -Wmo   # pose_i.y <-> pose_i+1.y\n",
    "        omega[pose_i+2][pose_i]     += -Wmo   # pose_i+1.x <-> pose_i.x\n",
    "        omega[pose_i+3][pose_i+1]   += -Wmo   # pose_i+1.y <-> pose_i.y\n",
    "        omega[pose_i+2][pose_i+2]   +=  Wmo   # pose_i+1.x <-> pose_i+1.x\n",
    "        omega[pose_i+3][pose_i+3]   +=  Wmo   # pose_i+1.y <-> pose_i+1.y\n",
    "\n",
    "        xi[pose_i]   += -Wmo * motion[0]\n",
    "        xi[pose_i+1] += -Wmo * motion[1]\n",
    "        xi[pose_i+2] +=  Wmo * motion[0]\n",
    "        xi[pose_i+3] +=  Wmo * motion[1]\n",
    "\n",
    "    ## TODO: After iterating through all the data\n",
    "    ## Compute the best estimate of poses and landmark positions\n",
    "    ## using the formula, omega_inverse * Xi\n",
    "    omega_inv = np.linalg.inv(omega)\n",
    "    mu = np.dot(omega_inv, xi)\n",
    "    \n",
    "    return mu # return `mu`\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Helper functions\n",
    "\n",
    "To check that your implementation of SLAM works for various inputs, we have provided two helper functions that will help display the estimated pose and landmark locations that your function has produced. First, given a result `mu` and number of time steps, `N`, we define a function that extracts the poses and landmarks locations and returns those as their own, separate lists. \n",
    "\n",
    "Then, we define a function that nicely print out these lists; both of these we will call, in the next step.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# a helper function that creates a list of poses and of landmarks for ease of printing\n",
    "# this only works for the suggested constraint architecture of interlaced x,y poses\n",
    "def get_poses_landmarks(mu, N):\n",
    "    # create a list of poses\n",
    "    poses = []\n",
    "    for i in range(N):\n",
    "        poses.append((mu[2*i].item(), mu[2*i+1].item()))\n",
    "\n",
    "    # create a list of landmarks\n",
    "    landmarks = []\n",
    "    for i in range(num_landmarks):\n",
    "        landmarks.append((mu[2*(N+i)].item(), mu[2*(N+i)+1].item()))\n",
    "\n",
    "    # return completed lists\n",
    "    return poses, landmarks\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_all(poses, landmarks):\n",
    "    print('\\n')\n",
    "    print('Estimated Poses:')\n",
    "    for i in range(len(poses)):\n",
    "        print('['+', '.join('%.3f'%p for p in poses[i])+']')\n",
    "    print('\\n')\n",
    "    print('Estimated Landmarks:')\n",
    "    for i in range(len(landmarks)):\n",
    "        print('['+', '.join('%.3f'%l for l in landmarks[i])+']')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run SLAM\n",
    "\n",
    "Once you've completed your implementation of `slam`, see what `mu` it returns for different world sizes and different landmarks!\n",
    "\n",
    "### What to Expect\n",
    "\n",
    "The `data` that is generated is random, but you did specify the number, `N`, or time steps that the robot was expected to move and the `num_landmarks` in the world (which your implementation of `slam` should see and estimate a position for. Your robot should also start with an estimated pose in the very center of your square world, whose size is defined by `world_size`.\n",
    "\n",
    "With these values in mind, you should expect to see a result that displays two lists:\n",
    "1. **Estimated poses**, a list of (x, y) pairs that is exactly `N` in length since this is how many motions your robot has taken. The very first pose should be the center of your world, i.e. `[50.000, 50.000]` for a world that is 100.0 in square size.\n",
    "2. **Estimated landmarks**, a list of landmark positions (x, y) that is exactly `num_landmarks` in length. \n",
    "\n",
    "#### Landmark Locations\n",
    "\n",
    "If you refer back to the printout of *exact* landmark locations when this data was created, you should see values that are very similar to those coordinates, but not quite (since `slam` must account for noise in motion and measurement)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "Estimated Poses:\n",
      "[50.000, 50.000]\n",
      "[66.781, 56.353]\n",
      "[86.294, 65.447]\n",
      "[89.215, 86.445]\n",
      "[71.317, 79.508]\n",
      "[52.428, 72.603]\n",
      "[33.140, 65.612]\n",
      "[13.356, 57.177]\n",
      "[31.238, 47.042]\n",
      "[49.500, 36.917]\n",
      "[67.007, 27.589]\n",
      "[83.626, 17.957]\n",
      "[99.354, 8.756]\n",
      "[78.655, 7.360]\n",
      "[58.955, 5.414]\n",
      "[40.669, 5.557]\n",
      "[21.331, 6.366]\n",
      "[0.991, 4.184]\n",
      "[4.836, 22.349]\n",
      "[9.038, 41.902]\n",
      "\n",
      "\n",
      "Estimated Landmarks:\n",
      "[17.417, 71.510]\n",
      "[26.067, 59.619]\n",
      "[37.983, 44.069]\n",
      "[30.703, 48.769]\n",
      "[69.844, 19.710]\n"
     ]
    }
   ],
   "source": [
    "# call your implementation of slam, passing in the necessary parameters\n",
    "mu = slam(data, N, num_landmarks, world_size, motion_noise, measurement_noise)\n",
    "\n",
    "# print out the resulting landmarks and poses\n",
    "if(mu is not None):\n",
    "    # get the lists of poses and landmarks\n",
    "    # and print them out\n",
    "    poses, landmarks = get_poses_landmarks(mu, N)\n",
    "    print_all(poses, landmarks)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Visualize the constructed world\n",
    "\n",
    "Finally, using the `display_world` code from the `helpers.py` file (which was also used in the first notebook), we can actually visualize what you have coded with `slam`: the final position of the robot and the positon of landmarks, created from only motion and measurement data!\n",
    "\n",
    "**Note that these should be very similar to the printed *true* landmark locations and final pose from our call to `make_data` early in this notebook.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Last pose:  (9.037968624479252, 41.902298826568156)\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABIoAAARfCAYAAABz4ghpAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzs3W3MZnddJ/Dv1d60YLyKFM44RSAq5aEYwGJaMiIIJVNaK1JIXaIhxi5byKLUtmGNBAkl8hRjmuILAhU3ljXGxYJtbEWmHQultAjGAg0PKmlYHpZ2Lh46vSkt7YxnX3hSQ5Dlvuea0/P7n/l83jn98r++7vrzxTdz6qLv+z4AAAAAHPGOmroAAAAAADUYigAAAABIYigCAAAAYGAoAgAAACCJoQgAAACAgaEIAAAAgCRbGIpe+9rXZteuXfnlX/7lB/7szjvvzLnnnpvTTz895557bvbv358k6fs+b3rTm7J79+688IUvzGc+85nxmgMAAABwWP3QoeglL3lJ3v3ud3/Pn1122WXZtWtX9uzZk127duWyyy5Lktxwww354he/mD179uQP/uAPcvHFF49SGgAAAIDD74cORaecckoe/vCHf8+f7d27N2effXaS5Oyzz8511133PX++WCzysz/7s7nrrruyb9++EWoDAAAAcLgd0r+j6Bvf+EZ27NiRJNmxY0e++c1vJknuuOOO7Ny584Hczp07c8cddxyGmgAAAACM7bD+y6z7vv++P1ssFofzJwAAAAAYycah/Ice+chHZt++fdmxY0f27duX448/Psm//w2i22+//YHc7bff/sDfPPrPrFabW/q9rlvONlulR2vZKj0qZLeT77plkvneXpUeFbJVerSWHevtFm+vSo8K2So9KmSr9Gjt9sZ8u7VslR4VslV6VLi9sXrMPVulR4VslR5Vsus6pL9RdNppp+XKK69Mklx55ZV5/vOf/z1/3vd9PvnJT2a5XP5/hyIAAAAA6vihf6Pooosuysc//vF861vfynOe85y8+tWvzite8YpccMEFueKKK3LCCSfk7W9/e5LkF3/xF/PhD384u3fvzsMe9rC85S1vGf2/AQAAAAAOjx86FF1yySX/6Z9ffvnl3/dni8Uib3jDG9ZvBQAAAMCD7rD+y6wBAAAAaJehCAAAAIAkhiIAAAAABoYi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slV6VLi9sXrMPVulR4VslR5Vsuvy6RkAAAAASQxFAAAAAAwMRQAAAAAkMRQBAAAAMDAUAQAAAJDEUAQAAADAwFAEAAAAQBJDEQAAAAADQxEAAAAASZJF3/f91CUAAAAAmN7GlD++Wm1uKdd1y9lmq/RoLVulR4XsdvJdt0wy39ur0qNCtkqP1rJjvd3i7VXpUSFbpUeFbJUerd3emG+3lq3So0K2So8KtzdWj7lnq/SokK3So0p2XT49AwAAACCJoQgAAACAgaEIAAAAgCSGIgAAAAAGhiIAAAAAkhiKAAAAABgYigAAAABIYigCAAAAYGAoAgAAACBJsuj7vp+6BAAAAADT25jyx1erzS3lum4522yVHq1lq/SokN1OvuuWSeZ7e1V6VMhW6dFadqy3W7y9Kj0qZKv0qJCt0qO12xvz7dayVXpUyFbpUeH2xuox92yVHhWyVXpUya7Lp2cAAAAAJDEUAQAAADAwFAEAAACQxFAEAAAAwMBQBAAAAECSNf+vnv3Zn/1Z/uqv/iqLxSJPfOIT89a3vjX79u3LRRddlP379+cpT3lK/vAP/zDHHHPM4eoLAAAAwEgO+W8U3XHHHXnPe96T973vfbn66qtz8ODBXHPNNfmjP/qj/OZv/mb27NmT4447LldcccXh7AsAAADASNb69OzgwYO59957c+DAgdx7773pui4f+9jH8oIXvCBJ8uIXvzh79+49LEUBAAAAGNei7/v+UP/Dl19+eS699NIce+yxedaznpXXve51eelLX5prr702SfK1r30t5513Xq6++urDVhgAAACAcRzy3yjav39/9u7dm7179+YjH/lI7rnnntxwww3fl1ssFmsVBAAAAODBccj/Muubbropj3nMY3L88ccnSU4//fTccsstueuuu3LgwIFsbGzk9ttvz44dO37gG6vV5pZ+q+uWs81W6dFatkqPCtnt5LtumWS+t1elR4VslR6tZcd6u8Xbq9KjQrZKjwrZKj1au70x324tW6VHhWyVHhVub6wec89W6VEhW6VHley6DvlvFD360Y/Opz71qdxzzz3p+z4333xzTjzxxDzzmc/MBz/4wSTJX//1X+e0005buyQAAAAA4zvkv1H09Kc/PS94wQvy4he/OBsbGznppJPy0pe+NM997nNz4YUX5tJLL81JJ52UX/3VXz2cfQEAAAAYySEP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AwAAAMAqm7Rt267mgR/96Edz9dVXZ+vWrUmSSy65JNdcc03e+MY3ruZjAAAAAFhlq/4VRT9sd5pMJqv9GAAAAABW2aoPRZs2bcrOnTv3/37Xrl3ZuHHjaj8GAAAAgFW26kPR8ccfn+uuuy7XX3999uzZk8suuywnn3zyaj8GAAAAgFW2sOoHLizkjW98Y37zN38z+/btywte8II84hGPWO3HAAAAALDKVv2bWf84O3bsyNatW3PPPffktNNOyxlnnHEgHw8HjW9/+9v5vd/7vXznO9/JmjVr8su//Mv59V//9dx000151atelW9961v5qZ/6qbz97W/PAx7wgKHrwtz5p/+y5Kijjsr555+f66+/PmeddVZuvvnmPPrRj84f//EfZ926dUPXhLlzyy235A1veEO+8Y1vZDKZ5JxzzsnDHvYwn33Qs/e+9735y7/8y0wmkzzykY/MW9/61uzevdtnH6yy173udbnyyitz5JFH5tJLL02Se/3PeG3bZuvWrbnqqqty6KGH5o/+6I9y3HHH/dhnrPqrZz/Kvn378uY3vzkXXHBBLrvsslx66aW59tprD2QFOGisXbs2r33ta/ORj3wkH/zgB/OBD3wg1157bbZt25aTTjopl19+eU466aRs27Zt6Kowly688MIce+yx+39/7rnn5iUveUkuv/zyrF+/PhdddNGA7WB+bd26NU95ylPy0Y9+NB/60Idy7LHH+uyDnu3atSsXXnhh/uqv/iqXXnpp9u3bl8suu8xnH/Tg+c9/fi644IL/7s/u7XNux44due6663L55ZfnD//wD/OmN71pSc84oEPRNddck4c+9KE5+uijs27dupx66qnZvn37gawAB42NGzfuX4uPOOKIHHPMMdm1a1e2b9+eLVu2JEm2bNmSj3/840PWhLm0c+fOXHnllXnhC1+Y5Hs/EfQzn/lMnvnMZyZJnve85/n8gx7ceuut+fznP7//7q1bty7r16/32QcHwL59+3LnnXfm7rvvzp133pmmaXz2QQ+e9KQn/cBXxd7b59w//flkMsnP/MzP5JZbbsnu3bt/7DMO6FC0a9eubNq0af/vjzrqqOzatetAVoCD0g033JCvfe1redzjHpfvfve7+38S4caNG/OP//iPA7eD+XPOOefkNa95Tdas+d7H7I033pj169dnYeF73xpw06ZNPv+gB9dff302bNiQ173uddmyZUvOPvvs3H777T77oGdHHXVUfuM3fiNPe9rT8uQnPzlHHHFEjjvuOJ99cIDc2+fcv9xglnoPD+hQ9MO+HdJkMjmQFeCgc9ttt+XMM8/M61//+hxxxBFD14G594lPfCIbNmzIYx7zmB+Z8/kHq+/uu+/OV7/61fzKr/xKLrnkkhx22GFeM4MD4Oabb8727duzffv2XH311bnjjjuyY8eOH8j57IMD675uMKv+U89+lE2bNmXnzp37f79r1679qxew+vbu3Zszzzwzz3nOc7J58+YkyZFHHpndu3dn48aN2b17dzZs2DBwS5gvX/ziF3PFFVdkx44dueuuu3Lrrbdm69atueWWW3L33XdnYWEhO3fu9PkHPdi0aVM2bdqUxz3ucUmSX/zFX8y2bdt89kHPPvWpT+UhD3nI/ru1efPmfOlLX/LZBwfIvX3O/csNZqn38IB+RdHxxx+f6667Ltdff3327NmTyy67LCeffPKBrAAHjbZtc/bZZ+eYY47J6aefvv/PTz755FxyySVJkksuuSRPf/rTh6oIc+nVr351duzYkSuuuCLnnXdeTjzxxLztbW/LCSeckI997GNJkosvvtjnH/SgaZps2rQp3/zmN5Mkn/70p3Psscf67IOe/eRP/mT+/u//PnfccUfats2nP/3pPPzhD/fZBwfIvX3O/dOft22bL3/5y5lOp0saiibtD/tapB5dddVVOeecc/b/2ODf/u3fPpCPh4PGF77whfzqr/5qHvnIR+7/PilnnXVWHvvYx+aVr3xlvv3tb+fBD35w3vGOd+SBD3zgwG1hPn32s5/Ne97znpx//vm5/vrr86pXvSo333xzHvWoR+Xcc8/1I4KhB1/72tdy9tlnZ+/evTn66KPz1re+Nffcc4/PPujZO9/5znz4wx/OwsJCHvWoR2Xr1q3ZtWuXzz5YZWeddVY+97nP5cYbb8yRRx6ZV7ziFXnGM57xQz/n2rbNm9/85lx99dU57LDDcs455+T444//sc844EMRAAAAADUd0FfPAAAAAKjLUAQAAABAEkMRAAAAAB1DEQAAAABJDEUAAAAAdAxFAAAAACQxFAEAAADQMRQBAAAAkCT5/wEnnzAyjkdVWAAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fae456e7e10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# import the helper function\n",
    "from helpers import display_world\n",
    "\n",
    "# Display the final world!\n",
    "\n",
    "# define figure size\n",
    "plt.rcParams[\"figure.figsize\"] = (20,20)\n",
    "\n",
    "# check if poses has been created\n",
    "if 'poses' in locals():\n",
    "    # print out the last pose\n",
    "    print('Last pose: ', poses[-1])\n",
    "    # display the last position of the robot *and* the landmark positions\n",
    "    display_world(int(world_size), poses[-1], landmarks)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Question: How far away is your final pose (as estimated by `slam`) compared to the *true* final pose? Why do you think these poses are different?\n",
    "\n",
    "You can find the true value of the final pose in one of the first cells where `make_data` was called. You may also want to look at the true landmark locations and compare them to those that were estimated by `slam`. Ask yourself: what do you think would happen if we moved and sensed more (increased N)? Or if we had lower/higher noise parameters."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Answer**: The difference is (9.04, 41.90) - [7.43 42.80] = (1.61, -0.90). They are different because of the uncertainties in motion and measurement. I imagine that if N were increased, the absolute error would go down because it generally depends inversely on N. Obviously if the noise were larger, the error would be worse, and conversely, smaller noise leads to less error."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Testing\n",
    "\n",
    "To confirm that your slam code works before submitting your project, it is suggested that you run it on some test data and cases. A few such cases have been provided for you, in the cells below. When you are ready, uncomment the test cases in the next cells (there are two test cases, total); your output should be **close-to or exactly** identical to the given results. If there are minor discrepancies it could be a matter of floating point accuracy or in the calculation of the inverse matrix.\n",
    "\n",
    "### Submit your project\n",
    "\n",
    "If you pass these tests, it is a good indication that your project will pass all the specifications in the project rubric. Follow the submission instructions to officially submit!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "Estimated Poses:\n",
      "[50.000, 50.000]\n",
      "[37.973, 33.652]\n",
      "[26.185, 18.155]\n",
      "[13.745, 2.116]\n",
      "[28.097, 16.783]\n",
      "[42.384, 30.902]\n",
      "[55.831, 44.497]\n",
      "[70.857, 59.699]\n",
      "[85.697, 75.543]\n",
      "[74.011, 92.434]\n",
      "[53.544, 96.454]\n",
      "[34.525, 100.080]\n",
      "[48.623, 83.953]\n",
      "[60.197, 68.107]\n",
      "[73.778, 52.935]\n",
      "[87.132, 38.538]\n",
      "[80.303, 20.508]\n",
      "[72.798, 2.945]\n",
      "[55.245, 13.255]\n",
      "[37.416, 22.317]\n",
      "\n",
      "\n",
      "Estimated Landmarks:\n",
      "[82.956, 13.539]\n",
      "[70.495, 74.141]\n",
      "[36.740, 61.281]\n",
      "[18.698, 66.060]\n",
      "[20.635, 16.875]\n"
     ]
    }
   ],
   "source": [
    "# Here is the data and estimated outputs for test case 1\n",
    "\n",
    "test_data1 = [[[[1, 19.457599255548065, 23.8387362100849], [2, -13.195807561967236, 11.708840328458608], [3, -30.0954905279171, 15.387879242505843]], [-12.2607279422326, -15.801093326936487]], [[[2, -0.4659930049620491, 28.088559771215664], [4, -17.866382374890936, -16.384904503932]], [-12.2607279422326, -15.801093326936487]], [[[4, -6.202512900833806, -1.823403210274639]], [-12.2607279422326, -15.801093326936487]], [[[4, 7.412136480918645, 15.388585962142429]], [14.008259661173426, 14.274756084260822]], [[[4, -7.526138813444998, -0.4563942429717849]], [14.008259661173426, 14.274756084260822]], [[[2, -6.299793150150058, 29.047830407717623], [4, -21.93551130411791, -13.21956810989039]], [14.008259661173426, 14.274756084260822]], [[[1, 15.796300959032276, 30.65769689694247], [2, -18.64370821983482, 17.380022987031367]], [14.008259661173426, 14.274756084260822]], [[[1, 0.40311325410337906, 14.169429532679855], [2, -35.069349468466235, 2.4945558982439957]], [14.008259661173426, 14.274756084260822]], [[[1, -16.71340983241936, -2.777000269543834]], [-11.006096015782283, 16.699276945166858]], [[[1, -3.611096830835776, -17.954019226763958]], [-19.693482634035977, 3.488085684573048]], [[[1, 18.398273354362416, -22.705102332550947]], [-19.693482634035977, 3.488085684573048]], [[[2, 2.789312482883833, -39.73720193121324]], [12.849049222879723, -15.326510824972983]], [[[1, 21.26897046581808, -10.121029799040915], [2, -11.917698965880655, -23.17711662602097], [3, -31.81167947898398, -16.7985673023331]], [12.849049222879723, -15.326510824972983]], [[[1, 10.48157743234859, 5.692957082575485], [2, -22.31488473554935, -5.389184118551409], [3, -40.81803984305378, -2.4703329790238118]], [12.849049222879723, -15.326510824972983]], [[[0, 10.591050242096598, -39.2051798967113], [1, -3.5675572049297553, 22.849456408289125], [2, -38.39251065320351, 7.288990306029511]], [12.849049222879723, -15.326510824972983]], [[[0, -3.6225556479370766, -25.58006865235512]], [-7.8874682868419965, -18.379005523261092]], [[[0, 1.9784503557879374, -6.5025974151499]], [-7.8874682868419965, -18.379005523261092]], [[[0, 10.050665232782423, 11.026385307998742]], [-17.82919359778298, 9.062000642947142]], [[[0, 26.526838150174818, -0.22563393232425621], [4, -33.70303936886652, 2.880339841013677]], [-17.82919359778298, 9.062000642947142]]]\n",
    "\n",
    "##  Test Case 1\n",
    "##\n",
    "# Estimated Pose(s):\n",
    "#     [50.000, 50.000]\n",
    "#     [37.858, 33.921]\n",
    "#     [25.905, 18.268]\n",
    "#     [13.524, 2.224]\n",
    "#     [27.912, 16.886]\n",
    "#     [42.250, 30.994]\n",
    "#     [55.992, 44.886]\n",
    "#     [70.749, 59.867]\n",
    "#     [85.371, 75.230]\n",
    "#     [73.831, 92.354]\n",
    "#     [53.406, 96.465]\n",
    "#     [34.370, 100.134]\n",
    "#     [48.346, 83.952]\n",
    "#     [60.494, 68.338]\n",
    "#     [73.648, 53.082]\n",
    "#     [86.733, 38.197]\n",
    "#     [79.983, 20.324]\n",
    "#     [72.515, 2.837]\n",
    "#     [54.993, 13.221]\n",
    "#     [37.164, 22.283]\n",
    "\n",
    "\n",
    "# Estimated Landmarks:\n",
    "#     [82.679, 13.435]\n",
    "#     [70.417, 74.203]\n",
    "#     [36.688, 61.431]\n",
    "#     [18.705, 66.136]\n",
    "#     [20.437, 16.983]\n",
    "\n",
    "\n",
    "### Uncomment the following three lines for test case 1 and compare the output to the values above ###\n",
    "\n",
    "mu_1 = slam(test_data1, 20, 5, 100.0, 2.0, 2.0)\n",
    "poses, landmarks = get_poses_landmarks(mu_1, 20)\n",
    "print_all(poses, landmarks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "Estimated Poses:\n",
      "[50.000, 50.000]\n",
      "[69.181, 45.665]\n",
      "[87.743, 39.703]\n",
      "[76.270, 56.311]\n",
      "[64.317, 72.176]\n",
      "[52.257, 88.154]\n",
      "[44.059, 69.401]\n",
      "[37.002, 49.918]\n",
      "[30.924, 30.955]\n",
      "[23.508, 11.419]\n",
      "[34.180, 27.133]\n",
      "[44.155, 43.846]\n",
      "[54.806, 60.920]\n",
      "[65.698, 78.546]\n",
      "[77.468, 95.626]\n",
      "[96.802, 98.821]\n",
      "[75.957, 99.971]\n",
      "[70.200, 81.181]\n",
      "[64.054, 61.723]\n",
      "[58.107, 42.628]\n",
      "\n",
      "\n",
      "Estimated Landmarks:\n",
      "[76.779, 42.887]\n",
      "[85.065, 77.438]\n",
      "[13.548, 95.652]\n",
      "[59.449, 39.595]\n",
      "[69.263, 94.240]\n"
     ]
    }
   ],
   "source": [
    "# Here is the data and estimated outputs for test case 2\n",
    "\n",
    "test_data2 = [[[[0, 26.543274387283322, -6.262538160312672], [3, 9.937396825799755, -9.128540360867689]], [18.92765331253674, -6.460955043986683]], [[[0, 7.706544739722961, -3.758467215445748], [1, 17.03954411948937, 31.705489938553438], [3, -11.61731288777497, -6.64964096716416]], [18.92765331253674, -6.460955043986683]], [[[0, -12.35130507136378, 2.585119104239249], [1, -2.563534536165313, 38.22159657838369], [3, -26.961236804740935, -0.4802312626141525]], [-11.167066095509824, 16.592065417497455]], [[[0, 1.4138633151721272, -13.912454837810632], [1, 8.087721200818589, 20.51845934354381], [3, -17.091723454402302, -16.521500551709707], [4, -7.414211721400232, 38.09191602674439]], [-11.167066095509824, 16.592065417497455]], [[[0, 12.886743222179561, -28.703968411636318], [1, 21.660953298391387, 3.4912891084614914], [3, -6.401401414569506, -32.321583037341625], [4, 5.034079343639034, 23.102207946092893]], [-11.167066095509824, 16.592065417497455]], [[[1, 31.126317672358578, -10.036784369535214], [2, -38.70878528420893, 7.4987265861424595], [4, 17.977218575473767, 6.150889254289742]], [-6.595520680493778, -18.88118393939265]], [[[1, 41.82460922922086, 7.847527392202475], [3, 15.711709540417502, -30.34633659912818]], [-6.595520680493778, -18.88118393939265]], [[[0, 40.18454208294434, -6.710999804403755], [3, 23.019508919299156, -10.12110867290604]], [-6.595520680493778, -18.88118393939265]], [[[3, 27.18579315312821, 8.067219022708391]], [-6.595520680493778, -18.88118393939265]], [[], [11.492663265706092, 16.36822198838621]], [[[3, 24.57154567653098, 13.461499960708197]], [11.492663265706092, 16.36822198838621]], [[[0, 31.61945290413707, 0.4272295085799329], [3, 16.97392299158991, -5.274596836133088]], [11.492663265706092, 16.36822198838621]], [[[0, 22.407381798735177, -18.03500068379259], [1, 29.642444125196995, 17.3794951934614], [3, 4.7969752441371645, -21.07505361639969], [4, 14.726069092569372, 32.75999422300078]], [11.492663265706092, 16.36822198838621]], [[[0, 10.705527984670137, -34.589764174299596], [1, 18.58772336795603, -0.20109708164787765], [3, -4.839806195049413, -39.92208742305105], [4, 4.18824810165454, 14.146847823548889]], [11.492663265706092, 16.36822198838621]], [[[1, 5.878492140223764, -19.955352450942357], [4, -7.059505455306587, -0.9740849280550585]], [19.628527845173146, 3.83678180657467]], [[[1, -11.150789592446378, -22.736641053247872], [4, -28.832815721158255, -3.9462962046291388]], [-19.841703647091965, 2.5113335861604362]], [[[1, 8.64427397916182, -20.286336970889053], [4, -5.036917727942285, -6.311739993868336]], [-5.946642674882207, -19.09548221169787]], [[[0, 7.151866679283043, -39.56103232616369], [1, 16.01535401373368, -3.780995345194027], [4, -3.04801331832137, 13.697362774960865]], [-5.946642674882207, -19.09548221169787]], [[[0, 12.872879480504395, -19.707592098123207], [1, 22.236710716903136, 16.331770792606406], [3, -4.841206109583004, -21.24604435851242], [4, 4.27111163223552, 32.25309748614184]], [-5.946642674882207, -19.09548221169787]]] \n",
    "\n",
    "\n",
    "##  Test Case 2\n",
    "##\n",
    "# Estimated Pose(s):\n",
    "#     [50.000, 50.000]\n",
    "#     [69.035, 45.061]\n",
    "#     [87.655, 38.971]\n",
    "#     [76.084, 55.541]\n",
    "#     [64.283, 71.684]\n",
    "#     [52.396, 87.887]\n",
    "#     [44.674, 68.948]\n",
    "#     [37.532, 49.680]\n",
    "#     [31.392, 30.893]\n",
    "#     [24.796, 12.012]\n",
    "#     [33.641, 26.440]\n",
    "#     [43.858, 43.560]\n",
    "#     [54.735, 60.659]\n",
    "#     [65.884, 77.791]\n",
    "#     [77.413, 94.554]\n",
    "#     [96.740, 98.020]\n",
    "#     [76.149, 99.586]\n",
    "#     [70.211, 80.580]\n",
    "#     [64.130, 61.270]\n",
    "#     [58.183, 42.175]\n",
    "\n",
    "\n",
    "# Estimated Landmarks:\n",
    "#     [76.777, 42.415]\n",
    "#     [85.109, 76.850]\n",
    "#     [13.687, 95.386]\n",
    "#     [59.488, 39.149]\n",
    "#     [69.283, 93.654]\n",
    "\n",
    "\n",
    "### Uncomment the following three lines for test case 2 and compare to the values above ###\n",
    "\n",
    "mu_2 = slam(test_data2, 20, 5, 100.0, 2.0, 2.0)\n",
    "poses, landmarks = get_poses_landmarks(mu_2, 20)\n",
    "print_all(poses, landmarks)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
